#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DBG_ENABLE
#define DBG_COLOR
#define DBG_LVL             DBG_INFO
#define DBG_SECTION_NAME    "web.utils"
#include <rtdbg.h>

#if WEBNET_SERVER_ENABLE

#include <dfs.h>
#include <arpa/inet.h> 
#include <netdev.h>
#include <webnet.h>
#include <wn_module.h>
#include <dfs_posix.h>
#include "app_dbg_drv.h"
#include "app_tool_cmd.h"
#include "app_tool_sm.h"
#include "app_system_msg.h"
#include "app_sys_param.h"
#include "app_ocpp_key_value.h"
#include "os_lib.h"
#include "dfs_private.h"
#include "web_utils.h"
#include "app_order_util.h"

#include "app_tool_api.h"
#include "web_tool_api.h"

#include "app_tool_api.h"
#include "web_tool_api.h"

#ifdef A5158_EDITION
#include "app_application_param.h"
#endif

#define FACTORY_LOG_PAGE_PWD        "56788765"

#define SYSTEM_CMD_LEN              128

#define UINT32_HIGH_16_MASK         0xFFFF0000
#define UINT32_LOW_16_MASK          0x0000FFFF

static char web_restart_param[][16] = {
    "ccm:model",
};

const static char *int_error = "Please input an integer";
const static char *number_error = "The input number format is incorrect";
const static char *forbidden = "Operation cannot be performed temporarily";

//check if 0-9 or '.'
static rt_bool_t is_number(char *str) 
{
    int dot = 0;
    
    for (int i = 0; i < strlen(str); i ++) {
        if (*(str + i) >= '0' && *(str + i) <= '9') {
            continue;
        }
        if (*(str + i) == '.') {
            dot ++;
            if (i == 0 || dot > 1) {
                return RT_FALSE;
            }
            continue;
        }
        return RT_FALSE;
    }
    return RT_TRUE;
}

//check if 0-9
static rt_bool_t is_int(char *str)
{
    for (int i = 0; i < strlen(str); i ++) {
        if (*(str + i) >= '0' && *(str + i) <= '9') {
            continue;
        }
        return RT_FALSE;
    }
    return RT_TRUE;
}

static char *skip_space_at_head(char *p)
{
    rt_uint16_t index = 0;
    
    while(*(p + index) == ' '  || 
          *(p + index) == '\t' ||
          *(p + index) == '\n' || 
          *(p + index) == '\r')
        index ++;
    
    return p + index;
}

static void space_to_plus_sign(char *str)
{
    char *ptr;
    
    while (1) {
        ptr = rt_strstr(str, " ");
        if (ptr != RT_NULL) {
            *ptr = '+';
            continue;
        }
        return;
    }
}

static void cgi_reboot_handler(struct webnet_session* session)
{
    if (app_system_reset_msg_post()) {
        webnet_session_printf(session, "Reboot successfully");
    } else {
        webnet_session_printf(session, "Reboot failed!");
    }
}

static void cgi_recovery_handler(struct webnet_session* session)
{    
    if (app_system_restore_factory_msg_post()) {
        webnet_session_printf(session, "Recover successfully");
    } else {
        webnet_session_printf(session, "Recover failed!");
    }    
}

static void cgi_factory_web_upload_handler(struct webnet_session* session)
{
    const char *mimetype;
    const char *factory_web_upload_html = WEB_FACTORY_UPLOAD_HTML;
    
    mimetype = mime_get_type(".html");
    webnet_session_set_header(session, mimetype, 200, "Ok", rt_strlen(factory_web_upload_html), RT_NULL);
    webnet_session_printf(session, factory_web_upload_html);
}

static void cgi_bind_config_handler(struct webnet_session* session)
{
#define _ACK_LEN_   1024
    
    char *buffer, *ack;
    struct webnet_request* request;
    
    if (session != RT_NULL) {
        request = session->request;
        
        buffer = (char *)rt_malloc(request->content_length + 1);
        if (buffer == RT_NULL) {
            return;
        }
        
        rt_memset(buffer, 0, request->content_length + 1);
        rt_strncpy(buffer, request->query, request->content_length);
        
        ack = (char *)rt_malloc(_ACK_LEN_);
        if (ack == RT_NULL) {
            LOG_E("no more memory for bind config");
            rt_free(buffer);
            return;
        }
        
        web_tool_sys_config(buffer, ack, _ACK_LEN_);
        
        webnet_session_printf(session, ack);        
        
        rt_free(buffer);
        rt_free(ack);
    } 
}

static void cgi_get_param_handler(struct webnet_session* session)
{
#define _GET_PARAM_RESP_LEN_ 1024
#define _VALUE_LEN_ 512
    
    int length, ret;
    struct webnet_request* request;
    char *key, *buffer, *resp, *value;
    const static char *error_value = "[error]";
    
    if (session != RT_NULL) {
        request = session->request;
        length = request->content_length;

        buffer = (char *)rt_malloc(length + 1);
        resp = (char *)rt_malloc(_GET_PARAM_RESP_LEN_ + 1);
        value = (char *)rt_malloc(_VALUE_LEN_ + 1);
    
        if (buffer == RT_NULL || resp == RT_NULL || value == RT_NULL) {
            goto __exit;
        } else {
            rt_memset(buffer, 0, length + 1);
            rt_memset(resp, 0, _GET_PARAM_RESP_LEN_ + 1);
            rt_memset(value, 0, _VALUE_LEN_ + 1);
        
            rt_strncpy(buffer, request->query, length);
            key = strtok(buffer, "\r\n");
            while (1) {
                if (key == RT_NULL) {
                    break;
                }
                ret = web_tool_get_param(key, value, _VALUE_LEN_);
                if (ret >= 0) {
                    if (_GET_PARAM_RESP_LEN_ - strlen(resp) > ret + 2) {
                        strncat(resp, value, ret);
                    } else {
                        LOG_E("no more memory for response info");
                        break;
                    }
                } else {
                    if (_GET_PARAM_RESP_LEN_ - strlen(resp) > strlen(error_value) + 2) {
                        strcat(resp, error_value);
                    } else {
                        LOG_E("no more memory for response info");
                        break;
                    }
                }
                strcat(resp, "\r\n");
                key = strtok(RT_NULL, "\r\n");
            }
        }
        webnet_session_printf(session, resp);
    }
    
__exit:
    
    if (buffer != RT_NULL) {
        rt_free(buffer);
    }
    
    if (resp != RT_NULL) {
        rt_free(resp);
    }
    
    if (value != RT_NULL) {
        rt_free(value);
    }
}


static void cgi_pre_upload_handler(struct webnet_session* session)
{
#define _PRE_UPLOAD_LEN_ 10
    
    static const char *ok = "okk";
    
    int event;
    uint8_t state;
    struct webnet_request* request;
    char content[_PRE_UPLOAD_LEN_] = {0};

    if (session != RT_NULL) {
        request = session->request;
    
        rt_strncpy(content, request->query, 
        strlen(request->query) > _PRE_UPLOAD_LEN_ - 1 ? _PRE_UPLOAD_LEN_ - 1 : strlen(request->query));
        event = atoi(content + 3) - 99;
    
        if (event == WEB_UPLOAD_SYS_FW) {
            if (app_order_get_charge_state(&state) != RT_EOK) {
                LOG_E("get ocpp status failed.");
                webnet_session_printf(session, forbidden);
                return;
            }
            
            switch (state) {
                case AVAILABLE:
                case UNAVAILABLE:
                case FAULTED:
                    break;
                
                default:
                    webnet_session_printf(session, forbidden);
                    LOG_E("%s.", forbidden);
                    return;
            }
        }
        
        webnet_session_printf(session, ok);
    }
}

static void cgi_maintain_handler(struct webnet_session* session)
{
    char *str, *cut;
    char ask[512] = {0};
    rt_uint8_t name_index;
    rt_uint32_t query_index;
    char cmd[SYSTEM_CMD_LEN] = {0};
    struct webnet_request* request;
    
    static const char* body = "<body onload=\"parent.location='../table/factory.shtml'\"></html>\r\n";

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            if (!strcmp(request->query_items[query_index].name, "cmd")) {
                str = request->query_items[query_index].value;
                if (!rt_strcmp(str, "")) {
                    webnet_session_printf(session, "Command cannot be empty");
                    return;
                }
                break;
            }
        }
        
        if (!rt_strcmp(str, FACTORY_LOG_PAGE_PWD)) {
            webnet_session_set_header(session, mime_get_type(".html"), 200, "Ok", -1, RT_NULL);
            webnet_session_printf(session, body);
            return;
        }
        
        cut = rt_strstr(str, "_dy_");
        
        if (cut != RT_NULL) {
            rt_memcpy(cmd, str, cut - str);
            strcat(cmd, "=");
            strcat(cmd, cut + 4);
        } else {
            rt_memcpy(cmd, str, rt_strlen(str));
        }
        strcat(cmd, "#");
        LOG_I("web command is %s",cmd);
        app_tool_info_set(cmd, DBG_CMD_MAINTAIN, app_dbg_drv_pkg_send_str);
        get_latest_param_set_ask(ask);
        webnet_session_printf(session, ask);
    }   
}

static void cgi_sync_time_handler(struct webnet_session* session)
{
    char *value;
    time_t real_time;
    struct tm *real_tm;
    char cmd[SYSTEM_CMD_LEN];
    struct webnet_request* request;
    rt_uint32_t query_index, name_index;

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            if (!strcmp(request->query_items[query_index].name, "timestamp")) {
                value = request->query_items[query_index].value;
                real_time = (time_t)(atoi(value));
                stime(&real_time);
                real_tm = localtime(&real_time);
                LOG_I("Sync time successfully.");
                webnet_session_printf(session, "Sync time successfully");
                return;
            }
        }
    }
}

#ifdef WHITE_CARD_LIST_ENABLE
static void cgi_rfid_delete_handler(struct webnet_session* session)
{
    local_list id;
    int ret, length;
    char buffer[IdTokenType] = {0};
    char temp_str[IdTokenType + 8];
    struct webnet_request* request;
	white_card_info white_card_list = {0};
    char ack[128 + (IdTokenType + 8) * 30] = {0};
    
    if (session != RT_NULL) {
        request = session->request;
        rt_memset(id.card_num, 0, sizeof(id.card_num));
        rt_memcpy(id.card_num, request->query, sizeof(id.card_num));
        ret = app_white_card_list_set(&id, CARD_DELETE_STATE); 
        
        switch (ret) {
            case OPERATE_OK:
                rt_snprintf(ack, sizeof(ack), "The card number (%s) is successfully deleted", id.card_num);
                break;
            
            case OPERATE_ERR:
                rt_snprintf(ack, sizeof(ack), "Card number (%s) could not be found", id.card_num);
                break;
            
            case CARD_NULL:        
            case CARD_LEN_ERR:
            default:
                rt_snprintf(ack, sizeof(ack), "System Error!", id.card_num);
                break;
        }
        
        /* add split sign */
        strcat(ack, "#");
        length = strlen(ack);
        
        app_apply_param_get(SYS_APPLY_WHITE_CARD_LIST, &white_card_list, sizeof(white_card_list));
        
        for (int n = 0; n < 30; n ++) {
            if (strlen(white_card_list.local_list_info[n].card_num) != 0) {
                rt_memset(temp_str, 0, sizeof(temp_str));
                rt_snprintf(temp_str, sizeof(temp_str), "card:%s\r\n", white_card_list.local_list_info[n].card_num);
                strncat((char *)ack + length, temp_str, strlen(temp_str));
                length += strlen(temp_str);
            }
        }
        
        webnet_session_printf(session, (const char *)ack);
    }
}

static void cgi_rfid_add_handler(struct webnet_session* session)
{
    char *ptr;
    char *buffer;
    local_list id;
    int i, j, ret;
    int length = 0;
    int err_flag = OPERATE_OK;
    char temp_str[IdTokenType + 8];
    struct webnet_request* request;
    char lines[30][IdTokenType] = {0};
	white_card_info white_card_list = {0};
    char ack[128 + (IdTokenType + 8) * 30] = {0};
    
    if (session != RT_NULL) {
        request = session->request;
        buffer = (char *)rt_malloc(request->content_length + 100);
        if (buffer == RT_NULL) {
            rt_snprintf(ack, sizeof(ack), "Too much input data, add failed");
            goto __exit;
        }
    
        rt_memset(buffer, 0, request->content_length + 100);
        rt_memcpy(buffer, request->query, request->content_length + 100);
        
        /*check input data*/
        ptr = strtok(buffer, "\n");
        for ( i = 0; i < 30; i ++) {
            if (ptr != RT_NULL) {
                if (strlen(ptr) >= IdTokenType) {
                    rt_snprintf(ack, sizeof(ack), "One of card numbers is more than 20 in length, add failed");
                    goto __exit;
                }
                rt_memcpy(lines[i], ptr, strlen(ptr));
                ptr = strtok(RT_NULL, "\n");
                continue;
            }
            break;
        }
        
        if (i > 30) {
            rt_snprintf(ack, sizeof(ack), "A maximum of 30 card numbers can be added, add failed");
            goto __exit;
        }
        
        for (j = 0; j < i; j ++) {
            rt_memset(&id.card_num, 0, sizeof(id.card_num));
            rt_memcpy(&id.card_num, lines[j], strlen(lines[j]));
            ret = app_white_card_list_set(&id, CARD_ADD_STATE);
            
            switch (ret) {
                case OPERATE_OK:
                    break;
                
                case CARD_FULL:
                    rt_snprintf(ack, sizeof(ack), "The local list is full, adding terminated at card number %s", lines[j]); 
                    goto __exit;
                
                case CARD_SAME:
                    break;
                
                case CARD_NULL:
                case OPERATE_ERR:
                case CARD_LEN_ERR:
                default:
                    rt_snprintf(ack, sizeof(ack), "System error at card number %s, adding terminated", lines[j]);
                    goto __exit;
            }
        }
        
        rt_snprintf(ack, sizeof(ack), "Add card number(s) success");    
        
__exit:
        
        /* add split sign */
        strcat(ack, "#");
        length = strlen(ack);
        
        app_apply_param_get(SYS_APPLY_WHITE_CARD_LIST, &white_card_list, sizeof(white_card_list));
        
        for (int n = 0; n < 30; n ++) {
            if (strlen(white_card_list.local_list_info[n].card_num) != 0) {
                rt_memset(temp_str, 0, sizeof(temp_str));
                rt_snprintf(temp_str, sizeof(temp_str), "card:%s\r\n", white_card_list.local_list_info[n].card_num);
                strncat((char *)ack + length, temp_str, strlen(temp_str));
                length += strlen(temp_str);
            }
        }
        
        length = strlen(ack);
        webnet_session_printf(session, (const char *)ack);
        
        if (buffer != RT_NULL) {
            rt_free(buffer);
        }
        
    }    
    
}

static void cgi_rfid_refresh_handler(struct webnet_session* session)
{
    int length = 0;
    char temp_str[IdTokenType + 8];
    white_card_info white_card_list = {0};
    rt_uint8_t buffer[(IdTokenType + 8) * 30] = {0};
        
    if (session != RT_NULL) {
        app_apply_param_get(SYS_APPLY_WHITE_CARD_LIST, &white_card_list, sizeof(white_card_list));
        
        for (int n = 0; n < 30; n ++) {
            if (strlen(white_card_list.local_list_info[n].card_num) != 0) {
                rt_memset(temp_str, 0, sizeof(temp_str));
                rt_snprintf(temp_str, sizeof(temp_str), "card:%s\r\n", white_card_list.local_list_info[n].card_num);
                strncat((char *)buffer + length, temp_str, strlen(temp_str));
                length += strlen(temp_str);
            }
        }
        
        webnet_session_printf(session, (const char *)buffer);
    }
}
#endif

static void cgi_ca_config_handler(struct webnet_session* session)
{
    rt_uint8_t i;
    char ack[150] = {0};
    rt_uint8_t name_index;
    rt_uint32_t query_index;
    char cmd[SYSTEM_CMD_LEN];
    char *value, *start, *cut;
    struct webnet_request* request;
    const char split[][4] = {"%3A",":"};
    
    static const char *str = "set ocpp certificate to %s %s.";

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            start = request->query_items[query_index].name;            
            for (i = 0; i < sizeof(split) / 4; i ++) {
                cut = rt_strstr(start, split[i]);                
                if (cut != RT_NULL ) {
                    break;
                }
            }
            
            if ( i == sizeof(split) / 4) {
                return;
            }
            
            value = request->query_items[query_index].value;
            if (web_tool_set_ocpp_cer_by_name(value)) {
                rt_snprintf(ack, sizeof(ack) - 1, str, value, "success");
            } else {
                rt_snprintf(ack, sizeof(ack) - 1, str, value, "failed");
            }
            
            webnet_session_printf(session, ack);
            
            return;
        }
    }
}

static void cgi_ca_refresh_handler(struct webnet_session* session)
{
    int length = 0;
    char buffer[512] = {0};
    ocpp_ca_info *ocpp_ca_inf;
    char cur_ocpp_ca[OCPP_CA_FILE_NAME];
        
    if (session != RT_NULL) {
        ocpp_ca_inf = (ocpp_ca_info *)rt_malloc(sizeof(ocpp_ca_info));
    
        if (ocpp_ca_inf != RT_NULL) {
            rt_memset(ocpp_ca_inf, 0, sizeof(ocpp_ca_info));
            web_tool_get_ocpp_cer_list(ocpp_ca_inf);
            web_tool_get_current_ocpp_cer(cur_ocpp_ca, sizeof(cur_ocpp_ca), ocpp_ca_inf);
            rt_snprintf(buffer, sizeof(buffer) - 1, "ocpp_ca:%s\r\n", cur_ocpp_ca);
            length = strlen(buffer);
            for (int i = 0; i < ocpp_ca_inf->ocpp_ca_count; i ++) {
                if (!rt_strcmp(cur_ocpp_ca, ocpp_ca_inf->ocpp_ca_list[i].filename)) {
                    continue;
                }
                rt_snprintf(buffer + length, sizeof(buffer) - length - 1, "ocpp_ca:%s\r\n", ocpp_ca_inf->ocpp_ca_list[i].filename);
                length = strlen(buffer);
            }
            rt_free(ocpp_ca_inf);
        }
        webnet_session_printf(session, (const char *)buffer);
    }
}

#ifdef OCPP_OFFLINE_KEY_ENABLE
static void cgi_ocpp_key_handler(struct webnet_session* session)
{
    rt_uint8_t i;
    rt_uint32_t temp;
    rt_uint32_t value;
    char ack[128] = {0};
    rt_uint8_t name_index;
    rt_uint32_t query_index;
    char web_resp[64] = {0};
    char cmd[SYSTEM_CMD_LEN];
    struct webnet_request* request;
    char *value_str, *start, *cut, *key;
    const char split[][4] = {"%3A",":"};
    
    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            
            start = request->query_items[query_index].name;
            
            for (i = 0; i < sizeof(split) / 4; i ++) {
                cut = rt_strstr(start, split[i]);
                
                if (cut != RT_NULL ) {
                    break;
                }
            }
            
            if ( i == sizeof(split) / 4) {
                return;
            }
            
            value_str = request->query_items[query_index].value;
            
            if (!rt_strcmp(value_str, "")) {
                webnet_session_printf(session, "Value cannot be empty");
                return;
            }
            
            if (!is_number(value_str)) {
                rt_snprintf(web_resp, strlen(number_error), number_error);
                goto __exit;
            }
            
            if (!is_int(value_str)) {
                rt_snprintf(web_resp, strlen(int_error), int_error);
                goto __exit;
            }
            
            
            key = start;
            value = atoi(value_str);
            
            if (!rt_strcmp(key, "OM:bit0")) {
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp));
                if (value != 0 && value != 1) {
                    return;
                }
                value = (temp & ~(1 << 0)) | (value << 0);
                ocpp_key_set_value(E_OCPP_KEY_OM, &value, sizeof(value));
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp)); 
                rt_snprintf(web_resp, sizeof(web_resp), "set %s, Keep Charging is %d", 
                    value == temp ? "success" : "failed", (temp >> 0) & 1);    
                goto __exit;  
            } else if (!rt_strcmp(key, "OM:bit1")) {
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp));
                if (value != 0 && value != 1) {
                    return;
                }
                value = (temp & ~(1 << 1)) | (value << 1);
                ocpp_key_set_value(E_OCPP_KEY_OM, &value, sizeof(value));
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp)); 
                rt_snprintf(web_resp, sizeof(web_resp), "set %s, Open New Deals is %d", 
                    value == temp ? "success" : "failed", (temp >> 1) & 1);   
                goto __exit;  
            } else if (!rt_strcmp(key, "OM:bit2")) {
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp));
                if (value != 0 && value != 1) {
                    return;
                }
                value = (temp & ~(1 << 2)) | (value << 2);
                ocpp_key_set_value(E_OCPP_KEY_OM, &value, sizeof(value));
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp)); 
                rt_snprintf(web_resp, sizeof(web_resp), "set %s, Way of Deals is %d", 
                    value == temp ? "success" : "failed", (temp >> 2) & 1);     
                goto __exit;    
            } else if (!rt_strcmp(key, "OM:bit3")) {
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp));
                if (value != 0 && value != 1) {
                    return;
                }
                value = (temp & ~(1 << 3)) | (value << 3);
                ocpp_key_set_value(E_OCPP_KEY_OM, &value, sizeof(value));
                ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp)); 
                rt_snprintf(web_resp, sizeof(web_resp), "set %s, Whitelist Mode is %d", 
                    value == temp ? "success" : "failed", (temp >> 3) & 1);       
                goto __exit;
            } else {
                LOG_E("no such key:[%s]", key);
                return;  
            }            
        }
        
        rt_snprintf(web_resp, sizeof(web_resp), "Parse form failed!");
       
    }
    
__exit:
    
     webnet_session_printf(session, web_resp);        
    
}
#endif

static void cgi_refresh_param_handler(struct webnet_session* session)
{
#define DEVICE_INFO_MAXLEN 1500
    
    int temp, length;
    char ip[18] ={0};
    char gw[18] ={0};
    char nm[18] ={0};
    char *param_info_get;
    char temp_str[128] = {0};
    struct netdev *netdev = RT_NULL;
    
    param_info_get = (char *)rt_malloc(DEVICE_INFO_MAXLEN);
    rt_memset(param_info_get, 0, DEVICE_INFO_MAXLEN);
    
    /* system param */
    app_tool_info_get((unsigned char *)param_info_get, DEVICE_INFO_MAXLEN - 1);
    length = strlen(param_info_get);
    
    /* ethernet config */
    netdev = netdev_get_by_name("e0");
    if (netdev != RT_NULL) {
        rt_strncpy(ip, inet_ntoa(netdev->ip_addr), sizeof(ip));
        rt_strncpy(gw, inet_ntoa(netdev->gw), sizeof(gw));
        rt_strncpy(nm, inet_ntoa(netdev->netmask), sizeof(nm));
        rt_snprintf(temp_str, sizeof(temp_str), "eth:dhcp=%d\r\neth:ip=%s\r\neth:gw=%s\r\neth:nm=%s\r\n",
            (netdev->flags & NETDEV_FLAG_DHCP) ? 1 : 0, ip, gw, nm);
        strncat((char *)param_info_get + length, temp_str, strlen(temp_str));
        length += strlen(temp_str);
    }
    
#ifdef OCPP_OFFLINE_KEY_ENABLE
    rt_memset(temp_str, 0, sizeof(temp_str));
    ocpp_key_get_value(E_OCPP_KEY_OM, &temp, sizeof(temp));
    rt_snprintf(temp_str, sizeof(temp_str), "OM:bit0=%d\r\nOM:bit1=%d\r\nOM:bit2=%d\r\nOM:bit3=%d\r\n",
        temp & 0x01, (temp & 0x02) >> 1, (temp & 0x04) >> 2, (temp & 0x08) >> 3);
    strncat((char *)param_info_get + length, temp_str, strlen(temp_str));
    length += strlen(temp_str);
    
    rt_memset(temp_str, 0, sizeof(temp_str));
    ocpp_key_get_value(E_OCPP_KEY_OCML, &temp, sizeof(temp));
    rt_snprintf(temp_str, sizeof(temp_str), "OCML:low=%d\r\nOCML:high=%d\r\n",
        temp & UINT32_LOW_16_MASK, (temp & UINT32_HIGH_16_MASK) >> 16 );
    strncat((char *)param_info_get + length, temp_str, strlen(temp_str));
    length += strlen(temp_str);
    
    rt_memset(temp_str, 0, sizeof(temp_str));
    ocpp_key_get_value(E_OCPP_KEY_MME, &temp, sizeof(temp));
    rt_snprintf(temp_str, sizeof(temp_str), "MME=%d\r\n",temp);
    strncat((char *)param_info_get + length, temp_str, strlen(temp_str));
    length += strlen(temp_str);
#endif
    
    char cur_ocpp_ca[OCPP_CA_FILE_NAME];
    
    web_tool_get_current_ocpp_cer(cur_ocpp_ca, sizeof(cur_ocpp_ca), RT_NULL);
    rt_memset(temp_str, 0, sizeof(temp_str));
    rt_snprintf(temp_str, sizeof(temp_str), "ocpp:ca=%s\r\n",cur_ocpp_ca);
    strncat((char *)param_info_get + length, temp_str, strlen(temp_str));
    length += strlen(temp_str);
    
    webnet_session_printf(session, (const char*)param_info_get);
    rt_free(param_info_get);
}

static void cgi_qrcode_handler(struct webnet_session* session)
{
    char *value;
    rt_uint8_t btn_flg;
    char sn[128] = {0};
    char ask[512] = {0};
    char cmd[SYSTEM_CMD_LEN] = {0};
    struct webnet_request* request;
    rt_uint32_t query_index, name_index;

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            if (!strcmp(request->query_items[query_index].name, "ui%3Aqrcode") ||
                !strcmp(request->query_items[query_index].name, "ui:qrcode")) {
                value = request->query_items[query_index].value;
                //value = skip_space_at_head(value);
                space_to_plus_sign(value);
            } else if (!strcmp(request->query_items[query_index].name, "qrcode_flg")) {
                btn_flg = atoi(request->query_items[query_index].value);
            }
        }
        
        if (btn_flg == 0) {
            value = "null";
        } else if (btn_flg == 1) {
            app_sys_param_get(APP_SYS_PARAM_SN, sn, sizeof(sn));
            if (!strcmp(sn, "")) {
                value = "null";
            } else {
                value = sn;
            }
        } else {
            if (!rt_strcmp(value, "")) {
                webnet_session_printf(session, "Value cannot be empty");
                return;
            }
        }
        rt_memcpy(cmd, "ui:qrcode", 9);
        strcat(cmd, "=");
        strcat(cmd, value);
        strcat(cmd, "#");
        LOG_I("web command is %s",cmd);
        app_tool_info_set(cmd, DBG_CMD_MAINTAIN, app_dbg_drv_pkg_send_str);
        get_latest_param_set_ask(ask);
        webnet_session_printf(session, ask);
    }
}

static void cgi_login_handler(struct webnet_session* session)
{    
    char *body;
    const char* mimetype;
    char *user, *pwd, *id;
    rt_uint32_t query_index;
    struct webnet_request* request;
    rt_bool_t is_phone = RT_FALSE;
    
    static const char* header = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=gb2312\"/></head>";
    static const char* body_pc = "<body onload=\"parent.location='../frame/frame0.html'\"></html>\r\n";
    static const char* body_phone = "<body onload=\"parent.location='../frame/frame1.html'\"></html>\r\n";
    
    static const char* mismatch = "Account or password error!";
    
    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            if (!strcmp(request->query_items[query_index].name, "username")) {
                user = request->query_items[query_index].value;
            } else if (!strcmp(request->query_items[query_index].name, "password")) {
                pwd = request->query_items[query_index].value;
            } else if (!strcmp(request->query_items[query_index].name, "id")) {
                id = request->query_items[query_index].value;
            }
        }
        
        if (rt_strstr(request->user_agent, "Android") || rt_strstr(request->user_agent, "android")) {
            if (rt_strstr(request->user_agent, "Mobile") || rt_strstr(request->user_agent, "mobile")) {
                is_phone = RT_TRUE;
            }
        }

        if (is_phone) {
            LOG_I("A mobile device user requests login via %s", request->host);
            body = (char *)body_phone;
        } else {
            LOG_I("A PC device user requests login via %s", request->host);
            body = (char *)body_pc;
        }
        
        if (web_tool_verify_user(user, pwd, id)) {
            mimetype = mime_get_type(".html");
            session->request->result_code = 200;
            webnet_session_set_header(session, mimetype, 200, "Ok", -1, id);
            webnet_session_printf(session, body);
        } else {
            webnet_session_printf(session, mismatch);
        }
    
    }
}

static void cgi_config_handler(struct webnet_session* session)
{
    rt_uint8_t i;
    char ack[150] = {0};
    rt_uint8_t name_index;
    rt_uint32_t query_index;
    char cmd[SYSTEM_CMD_LEN];
    char *value, *start, *cut;
    struct webnet_request* request;
    const char split[][4] = {"%3A",":"};

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            
            start = request->query_items[query_index].name;
            
            for (i = 0; i < sizeof(split) / 4; i ++) {
                cut = rt_strstr(start, split[i]);
                
                if (cut != RT_NULL ) {
                    break;
                }
            }
            
            if ( i == sizeof(split) / 4) {
                return;
            }
            
            value = request->query_items[query_index].value;
            //value = skip_space_at_head(value);
            space_to_plus_sign(value);
            
            if (!rt_strcmp(value, "")) {
                webnet_session_printf(session, "Value cannot be empty");
                return;
            }
            
            rt_memset(cmd, 0, sizeof(cmd));
            rt_memcpy(cmd, start, cut - start);
            strcat(cmd, ":");
            strcat(cmd, cut + rt_strlen(split[i]));
            strcat(cmd, "=");
            strcat(cmd, value);
            strcat(cmd, "#");
            LOG_I("web command is %s",cmd);
            app_tool_info_set(cmd, DBG_CMD_MAINTAIN, app_dbg_drv_pkg_send_str);            
            get_latest_param_set_ask(ack);
            
            for (int i = 0; i < sizeof(web_restart_param)/sizeof(web_restart_param[0]); i ++) {
                if (rt_strstr(cmd, web_restart_param[i])) {
                    strcat(ack, ", charger need to be restarted to take effect, restart now?");
                    break;
                }
            }
            
            webnet_session_printf(session, ack);
            
            return;
        }
        
        webnet_session_printf(session, "Command cannot be empty");        
    } 
}

#ifdef ETH_DHCP_SWITCH_ENABLE
static void cgi_ether_handler(struct webnet_session* session)
{
    rt_uint8_t i;
    char ack[150] = {0};
    rt_uint8_t name_index;
    rt_uint32_t query_index;
    char cmd[SYSTEM_CMD_LEN];
    char *value, *start, *cut;
    struct webnet_request* request;
    const char split[][4] = {"%3A",":"};

    if (session != RT_NULL) {
        request = session->request;
        
        for (query_index = 0; query_index < request->query_counter; query_index ++) {
            
            start = request->query_items[query_index].name;
            
            for (i = 0; i < sizeof(split) / 4; i ++) {
                cut = rt_strstr(start, split[i]);
                
                if (cut != RT_NULL ) {
                    break;
                }
            }
            
            if ( i == sizeof(split) / 4) {
                return;
            }
            
            value = request->query_items[query_index].value;
            
            if (!rt_strcmp(value, "")) {
                webnet_session_printf(session, "Value cannot be empty");
                return;
            }
            
            rt_memset(cmd, 0, sizeof(cmd));
            rt_memcpy(cmd, start, cut - start);
            strcat(cmd, ":");
            strcat(cmd, cut + rt_strlen(split[i]));
            strcat(cmd, "=");
            strcat(cmd, value);
            strcat(cmd, "#");
            LOG_I("web command is %s",cmd);
            app_tool_info_set(cmd, DBG_CMD_MAINTAIN, app_dbg_drv_pkg_send_str);            
            get_latest_param_set_ask(ack);
            
            if (rt_strstr(ack, "DHCP=1")) {
                eth_dhcp_enable(RT_TRUE);
            } else {
                eth_dhcp_enable(RT_FALSE);
            }
            
            webnet_session_printf(session, ack);
            
            return;
        }
        
        webnet_session_printf(session, "Command cannot be empty");        
    }
}
#endif

int webnet_start(void)
{
#ifdef WEBNET_USING_CGI
    webnet_cgi_register("login",            cgi_login_handler);
    webnet_cgi_register("get_param",        cgi_get_param_handler);
    webnet_cgi_register("pre_upload",       cgi_pre_upload_handler);
    webnet_cgi_register("config",           cgi_config_handler);
    webnet_cgi_register("bind_config",      cgi_bind_config_handler);
    webnet_cgi_register("reboot",           cgi_reboot_handler);
    webnet_cgi_register("recovery",         cgi_recovery_handler);
    webnet_cgi_register("maintain",         cgi_maintain_handler);
    webnet_cgi_register("qrcode",           cgi_qrcode_handler);
    webnet_cgi_register("sync_time",        cgi_sync_time_handler);
    webnet_cgi_register("refresh_param",    cgi_refresh_param_handler);
    webnet_cgi_register("ca_refresh",     cgi_ca_refresh_handler);
    webnet_cgi_register("ca_config",      cgi_ca_config_handler);
    webnet_cgi_register(WEB_FACTORY_UPLOAD_CGI_NAME,   cgi_factory_web_upload_handler);
    
#ifdef ETH_DHCP_SWITCH_ENABLE
    webnet_cgi_register("ether",            cgi_ether_handler);
#endif
    
#ifdef OCPP_OFFLINE_KEY_ENABLE
    webnet_cgi_register("ocpp_key",         cgi_ocpp_key_handler);
#endif
    
#ifdef WHITE_CARD_LIST_ENABLE
    webnet_cgi_register("rfid_delete",      cgi_rfid_delete_handler);
    webnet_cgi_register("rfid_add",         cgi_rfid_add_handler);
    webnet_cgi_register("rfid_refresh",     cgi_rfid_refresh_handler);
#endif
    
#endif
    
#ifdef WEBNET_USING_UPLOAD
    extern const struct webnet_module_upload_entry upload_entry_upload;

    webnet_upload_add(&upload_entry_upload);
#endif
    return webnet_init();
}
INIT_APP_EXPORT(webnet_start);

#ifdef RT_USING_FINSH
MSH_CMD_EXPORT(webnet_start, webserver start);
#endif

#endif
